/**
 * opportunity服务实现
 *
 * @author sxf
 * @email sxf02615@163.com
 * @date 2025/1/15
 */
package com.sxf.crm.service.impl;


import com.sxf.crm.entity.Opportunity;
import com.sxf.crm.entity.User;
import com.sxf.crm.enums.OpportunityStatus;
import com.sxf.crm.exception.BusinessException;
import com.sxf.crm.repository.OpportunityRepository;
import com.sxf.crm.service.OpportunityService;
import com.sxf.crm.service.UserService;
import com.sxf.crm.service.OpportunityFollowUpService;
import com.sxf.crm.service.OpportunityLogService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

import org.springframework.beans.BeanUtils;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.sxf.crm.dto.OpportunityDTO;
import com.sxf.crm.dto.OpportunityFollowUpDTO;
import com.sxf.crm.dto.OpportunityFollowUpRequest;

import java.util.List;

/**
 * 商机服务实现类
 * 
 * <p>实现商机相关的业务逻辑</p>
 * 
 * @author sxf
 * @email sxf02615@163.com
 * @date 2025/6/1
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class OpportunityServiceImpl implements OpportunityService {

    private final OpportunityRepository opportunityRepository;
    private final UserService userService;
    private final OpportunityLogService opportunityLogService;
    private final OpportunityFollowUpService opportunityFollowUpService;

    @Override
    @Transactional
    public Opportunity create(Opportunity opportunity, Long currentUserId) {
        log.info("开始创建商机: name={}", opportunity.getName());
        
        opportunity.setStatus(OpportunityStatus.UNASSIGNED);
        opportunity.setCreateAt(System.currentTimeMillis());
        opportunity.setCreateUserId(currentUserId);
        Opportunity saved = opportunityRepository.save(opportunity);
        
        // 记录创建日志 
        User creator = userService.getUserById(currentUserId);
        opportunityLogService.logCreate(saved, creator, opportunity.getName());
        
        log.info("商机创建成功: id={}", saved.getId());
        return saved;
    }

    @Override
    @Transactional
    public Opportunity update(Opportunity opportunity, Long currentUserId) {
        log.info("开始更新商机: id={}", opportunity.getId());
        
        // 记录原状态
        Opportunity oldOpportunity = getById(opportunity.getId());
        OpportunityStatus beforeStatus = oldOpportunity.getStatus();
        
        opportunity.setUpdateAt(System.currentTimeMillis());
        Opportunity updated = opportunityRepository.save(opportunity);
        
        // 如果状态发生变化，记录日志
        if (beforeStatus != updated.getStatus()) {
            User operator = userService.getUserById(currentUserId);
            opportunityLogService.logStatusChange(updated, operator, beforeStatus, updated.getStatus());
        }
        
        log.info("商机更新成功: id={}", updated.getId());
        return updated;
    }

    @Override
    public Opportunity getById(Long id) {
        return opportunityRepository.findById(id)
            .orElseThrow(() -> new BusinessException("商机不存在: " + id));
    }

    @Override
    public Page<Opportunity> findAll(Pageable pageable) {
        return opportunityRepository.findAll(pageable);
    }

    @Override
    @Transactional
    public Opportunity claim(Long id, String remark, Long currentUserId) {  
        log.info("开始认领商机: id={}, remark={}", id, remark);
        
        Opportunity opportunity = getById(id);
        if (!opportunity.getStatus().canBeClaimed()) {
            throw new BusinessException("当前状态不可认领");
        }

        User user = userService.getUserById(currentUserId);

        opportunity.setOwner(user);
        opportunity.setStatus(OpportunityStatus.CLAIMED);
        opportunity.setUpdateAt(System.currentTimeMillis());
        opportunity.setUpdateUserId(currentUserId);

        Opportunity updated = opportunityRepository.save(opportunity);
        log.info("商机认领成功: id={}", updated.getId());

        User operator = userService.getUserById(currentUserId);
        opportunityLogService.logClaim(opportunity, operator, user, remark);

        return updated;
    }

    @Override
    @Transactional
    public Opportunity assign(Long id, Long userId, String remark, Long currentUserId) {
        log.info("开始分配商机: id={}, userId={}", id, userId);
        
        Opportunity opportunity = getById(id);
        if (!opportunity.getStatus().canBeAssigned()) {
            throw new BusinessException("当前状态不可分配");
        }   

        User user = userService.getUserById(userId);
        
        // 记录原状态
        OpportunityStatus beforeStatus = opportunity.getStatus();

        opportunity.setOwner(user);
        opportunity.setStatus(OpportunityStatus.ASSIGNED_UNCLAIMED);
        opportunity.setUpdateAt(System.currentTimeMillis());
        opportunity.setUpdateUserId(currentUserId);

        Opportunity updated = opportunityRepository.save(opportunity);
        
        // 记录分配日志
        User operator = userService.getUserById(currentUserId);
        opportunityLogService.logAssign(updated, operator, user, remark);
        if(beforeStatus!=OpportunityStatus.ASSIGNED_UNCLAIMED){
            opportunityLogService.logStatusChange(opportunity, operator, beforeStatus, OpportunityStatus.ASSIGNED_UNCLAIMED);
        }

        log.info("商机分配成功: id={}", updated.getId());
        return updated;
    }

    @Override
    @Transactional
    public Opportunity recycle(Long id, String recycleReason, Long currentUserId) {
        log.info("开始回收商机: id={}", id);
        
        Opportunity opportunity = getById(id);
        if (!opportunity.getStatus().canBeRecycled()) {
            throw new BusinessException("当前状态不可回收");
        }

        OpportunityStatus beforeStatus = opportunity.getStatus();
        opportunity.setOwner(null);
        opportunity.setStatus(OpportunityStatus.RECYCLED);
        opportunity.setUpdateAt(System.currentTimeMillis());
        opportunity.setUpdateUserId(currentUserId);
        opportunity.setRecycleUserId(currentUserId);
        opportunity.setRecycleTime(System.currentTimeMillis());
        opportunity.setRecycleReason(recycleReason);
        opportunity.setRecycled(true);

        Opportunity updated = opportunityRepository.save(opportunity);
        log.info("商机回收成功: id={}", updated.getId());

        User operator = userService.getUserById(currentUserId);
        opportunityLogService.logRecycle(opportunity, operator, recycleReason);

        opportunityLogService.logStatusChange(opportunity, operator, beforeStatus, OpportunityStatus.RECYCLED);
        return updated;
    }

   
    @Override
    public List<OpportunityFollowUpDTO> listByOpportunityId(Long id) {
        return opportunityFollowUpService.listByOpportunityId(id);  
    }

    @Override
    public OpportunityFollowUpDTO addFollowUp(Long id, OpportunityFollowUpRequest request, Long currentUserId) {
        return opportunityFollowUpService.addFollowUp(id, request, currentUserId);
    }

    public OpportunityDTO convertToDTO(Opportunity opportunity) {
        if (opportunity == null) {
            return null;
        }
        OpportunityDTO dto = new OpportunityDTO();
        BeanUtils.copyProperties(opportunity, dto);

        // 设置客户信息
        if (opportunity.getCustomer() != null) {
            dto.setCustomerName(opportunity.getCustomer().getName());
            dto.setCustomerId(opportunity.getCustomer().getId());

        }

        // 设置联系人信息
        if (opportunity.getContact() != null) {
            dto.setContactName(opportunity.getContact().getName());
            dto.setContactId(opportunity.getContact().getId());
        }
        if(opportunity.getOwner()!=null){
            dto.setOwnerName(opportunity.getOwner().getUsername());
            dto.setOwnerId(opportunity.getOwner().getId());
        }
        if(opportunity.getCreateUserId()!=null){
            User user = userService.getUserById(opportunity.getCreateUserId());
            dto.setCreateUserName(user.getUsername());
            dto.setCreateUserId(opportunity.getCreateUserId());
        }
        if(opportunity.getUpdateUserId()!=null){
            User user = userService.getUserById(opportunity.getUpdateUserId());
            dto.setUpdateUserName(user.getUsername());
            dto.setUpdateUserId(opportunity.getUpdateUserId());
        }

        if(opportunity.getStatus()!=null){
            dto.setStatusLabel(opportunity.getStatus().getDescription());
            dto.setStatus(opportunity.getStatus().getDescription());
        }

        if(opportunity.getSource()!=null){
            dto.setSource(opportunity.getSource().name());
            dto.setSourceLabel(opportunity.getSource().getDescription());
        }

        return dto;
    }

    @Override
    public Opportunity accept(Long id, Long currentUserId) {
        Opportunity opportunity = getById(id);
        opportunity.setStatus(OpportunityStatus.ACCEPTED);
        opportunityRepository.save(opportunity);

        User operator = userService.getUserById(currentUserId);
        opportunityLogService.logAccept(opportunity, operator, opportunity.getOwner());


        opportunityLogService.logStatusChange(opportunity, opportunity.getOwner(), OpportunityStatus.ASSIGNED_UNCLAIMED, OpportunityStatus.ACCEPTED);
        return opportunity;
    }

    @Override
    public Opportunity reject(Long id, String rejectReason, Long currentUserId) {
        Opportunity opportunity = getById(id);
        opportunity.setStatus(OpportunityStatus.REJECTED);
        opportunity.setUpdateAt(System.currentTimeMillis());
        opportunity.setUpdateUserId(currentUserId);
        opportunity.setOwner(null);
        opportunity.setRejectReason(rejectReason);  
        opportunity.setRejectUserId(currentUserId);
        opportunity.setRejectTime(System.currentTimeMillis());
        opportunityRepository.save(opportunity);

        User operator = userService.getUserById(currentUserId);
        opportunityLogService.logReject(opportunity, operator, opportunity.getOwner(),rejectReason);

        opportunityLogService.logStatusChange(opportunity, opportunity.getOwner(), OpportunityStatus.ASSIGNED_UNCLAIMED, OpportunityStatus.REJECTED);
        return opportunity;
    }

    @Override
    public Opportunity lost(Long id, String lostReason, Long currentUserId) {
        Opportunity opportunity = getById(id);
        opportunity.setStatus(OpportunityStatus.LOST);
        opportunity.setUpdateAt(System.currentTimeMillis());
        opportunity.setUpdateUserId(currentUserId);
        opportunity.setLostReason(lostReason);
        opportunityRepository.save(opportunity);

        User operator = userService.getUserById(currentUserId);
        opportunityLogService.logLost(opportunity, operator, lostReason);

        opportunityLogService.logStatusChange(opportunity, opportunity.getOwner(), OpportunityStatus.ASSIGNED_UNCLAIMED, OpportunityStatus.LOST);
        return opportunity;
    }

    @Override
    public Opportunity won(Long id, String remark, Long currentUserId) {
        Opportunity opportunity = getById(id);
        opportunity.setStatus(OpportunityStatus.WON);
        opportunityRepository.save(opportunity);

        User operator = userService.getUserById(currentUserId);
        opportunityLogService.logWon(opportunity, operator, remark);

        opportunityLogService.logStatusChange(opportunity, opportunity.getOwner(), OpportunityStatus.ASSIGNED_UNCLAIMED, OpportunityStatus.WON);
        return opportunity;
    }

    @Override
    public Opportunity negotiating(Long id, String remark, Long currentUserId) {
        Opportunity opportunity = getById(id);
        opportunity.setStatus(OpportunityStatus.NEGOTIATING);
        opportunityRepository.save(opportunity);

        User operator = userService.getUserById(currentUserId);
        opportunityLogService.logNegotiating(opportunity, operator, remark);

        opportunityLogService.logStatusChange(opportunity, opportunity.getOwner(), OpportunityStatus.ASSIGNED_UNCLAIMED, OpportunityStatus.NEGOTIATING);
        return opportunity;
    }

    @Override
    public Opportunity pendingDecision(Long id, String remark, Long currentUserId) {
        Opportunity opportunity = getById(id);
        opportunity.setStatus(OpportunityStatus.PENDING_DECISION);
        opportunityRepository.save(opportunity);

        User operator = userService.getUserById(currentUserId);
        opportunityLogService.logFollowUp(opportunity, operator, remark);
        opportunityLogService.logPendingDecision(opportunity, operator);

        opportunityLogService.logStatusChange(opportunity, opportunity.getOwner(), OpportunityStatus.ASSIGNED_UNCLAIMED, OpportunityStatus.PENDING_DECISION);
        return opportunity;
    }

    @Override
    public Opportunity inProgress(Long id, String remark, Long currentUserId) {
        Opportunity opportunity = getById(id);
        opportunity.setStatus(OpportunityStatus.IN_PROGRESS);
        opportunityRepository.save(opportunity);

        User operator = userService.getUserById(currentUserId);
        opportunityLogService.logFollowUp(opportunity, operator, remark);
        opportunityLogService.logStatusChange(opportunity, opportunity.getOwner(), OpportunityStatus.ASSIGNED_UNCLAIMED, OpportunityStatus.IN_PROGRESS);
        return opportunity;
    }

    @Override
    public Opportunity followedUp(Long id, String remark, Long currentUserId) {
        Opportunity opportunity = getById(id);
        opportunity.setStatus(OpportunityStatus.FOLLOWED_UP);
        opportunityRepository.save(opportunity);

        User operator = userService.getUserById(currentUserId);
        opportunityLogService.logFollowUp(opportunity, operator, remark);
        opportunityLogService.logStatusChange(opportunity, opportunity.getOwner(), OpportunityStatus.ASSIGNED_UNCLAIMED, OpportunityStatus.FOLLOWED_UP);
        return opportunity;
    }
}